/********************************************************************************
* @file    g_sensor_core.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-08-21
* @brief   参考: http://blog.sina.com.cn/s/blog_17029604f0102wxtp.html
[校准原理]
首先，这个校准的过程是手动的（类似手机上的传感器校准），把模块水平放置（这个水平也只是个大概，如果要求高的话，还需要其他仪器辅助），
那么x轴和y轴的度数应该为0g，
获取此时的实际x轴和y轴的度数，假设是20和-17。
要注意此时传感器的量程和分辨率，假设此时adxl345是常规量程 -16g，分辨率13位，
那么此时度数的系数应该是1g/256 *1000 = 3.9 mg/LSB，（手册第三页数据表）
从数据手册上可以查到 偏移寄存器的比例因子是 15.6mg/LSB（固定的，与量程无关）
那么需要设定的实际偏移值就是 20/4 = 5和-17/4 = 4（15.6/3.9约为4）
然后取两个值的补码，分别为0x05和0xFB，写入对应的偏移寄存器。
这样，每次从传感器读取的数值就自动加上了这个设置的偏移。
z轴的偏移值检测方式一样，把z轴水平放置（处于0g场）。
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#include "bsp_i2c.h"
/* Private includes ----------------------------------------------------------*/
#include "g_sensor_core.h"
#include "adxl34x.h"
#include "log.h"
/* Private define ------------------------------------------------------------*/
#define ADXL345_DEVICE_ID 0XE5
#define ADXL346_DEVICE_ID 0XE6
/* Private typedef -----------------------------------------------------------*/
static const g_sensor_cfg_t g_sensor_info =
{
    .i2c_bus  = I2C_BUS0,
    .dev_addr = 0xA6,
};
uint8_t device_version = 0; // 记录传感器版本
uint8_t ret = 0;
uint8_t xyx_data[6] = {0};

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Public function prototypes -----------------------------------------------*/
static uint8_t i2c_read_byte(uint8_t reg_addr, uint8_t *r_data)
{
    return bsp_i2c_read_byte(g_sensor_info.i2c_bus, g_sensor_info.dev_addr,
                             reg_addr, r_data);
}

static uint8_t i2c_read_nbyte(uint8_t reg_addr, uint8_t *r_data, uint8_t r_len)
{
    return bsp_i2c_read_nbyte(g_sensor_info.i2c_bus, g_sensor_info.dev_addr,
                              &reg_addr, 1, r_data, r_len);
}

static uint8_t i2c_write_byte(uint8_t reg_addr, uint8_t w_data)
{
    return bsp_i2c_write_byte(g_sensor_info.i2c_bus, g_sensor_info.dev_addr,
                              reg_addr, w_data);
}

/**
 * @brief  读取传感器版本，用于判断器件是否可用
 * @note   NULL
 * @retval 0--失败 1--成功
 */
bool g_sensor_get_version(void)
{
    i2c_read_byte(REG_DEVICE_ID, &device_version);
    //LOG_D("ADXL:0x%02x\r\n", device_id_val);
    if (device_version != ADXL345_DEVICE_ID && device_version != ADXL346_DEVICE_ID)
    {
        return false;
    }
    return true;
}

/**
 * @brief  设置活动/静止时的值，和哪三轴可以触发中断
 * @note   NULL
 * @param  activity_val: 活动阈值 变化幅度
 * @param  activity_time_ms: 活动阈值时间 单位：ms
 * @param  static_val: 静止阈值 变化幅度
 * @param  static_time_s: 静止时间 单位：s
 * @param  axis:
 * * [7bit] 活动检测 0--直接REG_THRESH_ACT比较  1--相对值达到REG_THRESH_ACT
 * * [6bit] X_EN [5bit] Y_EN [4bit] Z_EN
 * * [3bit] 静止检测 0--直接REG_THRESH_INACT比较  1--相对值达到REG_THRESH_INACT
 * * [2bit] X_EN [1bit] Y_EN [0bit] Z_EN
 * @retval None
 */
void g_sensor_irq_trigger_para(uint8_t activity_val, uint8_t activity_time_ms,
                               uint8_t static_val, uint8_t static_time_s, uint8_t axis)
{
    // 活动阈值 变化幅度
    i2c_write_byte(REG_THRESH_ACT, activity_val);
    // 活动阈值时间 单位：ms
    i2c_write_byte(REG_DUR, activity_time_ms);
    // 静止阈值
    i2c_write_byte(REG_THRESH_INACT, static_val);
    // 静止时间     单位：s
    i2c_write_byte(REG_TIME_INACT, static_time_s);
    // 活动静止任意轴选择 选择三轴使能
    i2c_write_byte(REG_ACT_INACT_CTL, axis);
}

/**
 * @brief  传感器进入睡眠状态,如果之前配置了中断，那么就会清除中断功能
 * @note   如果想要中断唤醒，则先使用本函数，再调用g_sensor_set_low_power_awaken
 * @retval None
 */
void g_sensor_enter_sleep(void)
{
    // 中断清零前,应读取ACT_TAP_STATUS寄存器
    i2c_read_byte(REG_ACT_TAP_STATUS, &ret);
    // 读取中断标志寄存器，读一次清空一次中断标记
    i2c_read_byte(REG_INT_SOURCE, &ret);
    // 禁用 中断功能
    i2c_write_byte(REG_INT_ENABLE, 0x00);
    // 设置时需进入休眠模式 1HZ采集一次
    i2c_write_byte(REG_POWER_CTL, 0x01);
}

/**
 * @brief  配置加速度传感器，活动触发中断(用于低功耗唤醒)，需要先配置g_sensor_irq_trigger_para
 * @note   NULL
 * @retval None
 */
void g_sensor_set_low_power_awaken(void)
{
    g_sensor_enter_sleep();
    // 使能 中断 ININ1
    i2c_write_byte(REG_INT_MAP, 0x00);
    // 寄存器0x31—DATA_FORMAT(读/写)--中断设为高电平有效--全分辨率模式--右对齐模式--+16g
    i2c_write_byte(REG_DATA_FORMAT, 0x0B);
    i2c_write_byte(REG_INT_ENABLE, 0x10);  // 开启动态中断模式，19页
}

/**
 * @brief  传感器开始工作采集[FIFO流模式]
 * @note   流程：设置流模式--进入待机状态--进入测试状态
 * @retval None
 */
void g_sensor_open_sample(void)
{
    // FIFO流模式 将触发模式下的触发事件链接至INT2(这个中断脚没有使用)
    i2c_write_byte(REG_FIFO_CTL, 0xA8);
    // 待机模式
    i2c_write_byte(REG_POWER_CTL, 0x00);
    // 测量模式
    i2c_write_byte(REG_POWER_CTL, 0x08);
}

/**
 * @brief  读取一次传感器值
 * @note   NULL
 * @retval 0--失败 1--成功
 */
bool g_sensor_get_data(short *x, short *y, short *z)
{
    if (i2c_read_nbyte(REG_DATAX0, xyx_data, 6) != 0)
    {
        return false;
    }
    *x = xyx_data[1] << 8 | xyx_data[0];
    *y = xyx_data[3] << 8 | xyx_data[2];
    *z = xyx_data[5] << 8 | xyx_data[4];
    return true;
}

/**
 * @brief  设置传感器offset值(一次性，器件掉电或重启需要重新设置)
 * @note   -16g，分辨率13位，系数应该是1g/256 *1000 = 3.9 mg/LSB，（手册第三页数据表）
            偏移寄存器的比例因子是 15.6mg/LSB（固定的，与量程无关） 那么需要设定的实际偏移值就是 x/4（15.6/3.9约为4）
 * @retval 0--失败 1--成功
 */
bool g_sensor_set_offset(short *x, short *y, short *z)
{
    // 设置X轴偏移量
    i2c_write_byte(REG_OFSX, (char)(-(*x / 4)));
    // 设置Y轴偏移量
    i2c_write_byte(REG_OFSY, (char)(-(*y / 4)));
    // 设置Z轴偏移量
    i2c_write_byte(REG_OFSZ, (char)(-(*z / 4)));
    return true;
}
